package org.zhuzx.util;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

/**
 * 统一常量集
 * @author	zhuzx	2017年1月2日
 */
@SuppressWarnings("unchecked")
public class UnifiedConstants {
	
	/** 二元判断标志位，用以表示：肯定、正确、存在、正常、成功、真、好，以及其它类似的正面语义。 */
	public static final int FLAG_AFFIRMATIVE = 1;
	
	/** 二元判断标志位，用以表示：否定、错误、没有、异常、失败、假、坏，以及其它类似的负面语义。 */
	public static final int FLAG_NEGATIVE = 0;
	
	/**
	 * 根节点值，用于表示树形结构中的根节点，这个节点具备业务上的唯一性和特殊性；
	 * 或者这个节点本身并不存在，但需要作为一个虚拟节点供其它节点引用。<br>
	 * 举例：公司的部门是一个树形结构，一级部门再往上面就是代表公司全员的xx公司，
	 * 可以把一级部门的父部门id设置为ROOT_VALUE（xx公司是业务层面上的正宗根节点但没有数据实体），
	 * 若xx公司本身也作为一个部门数据存在（也就是它本身已经有实际的id值），
	 * 这时可以把xx公司这条数据的父部门id设置为ROOT_VALUE（这个父部门是虚拟节点）。
	 */
	public static final int ROOT_VALUE = 0;

	/** 一天的毫秒数 */
	public static final long MILLIS_OF_DAY = 1000L * 60 * 60 * 24;
	
	/** IO传输缓冲区大小 */
	public static final int IO_BUFFER_SIZE = 8192;
	
	/** SQL的in子句括号中的最大数量 */
	public static final int SQL_IN_MAX_NUM = 200;
	
	public static final String REGEX_DATE = "\\d{4}-\\d{2}-\\d{2}";
	public static final String REGEX_TIME = "\\d{2}:\\d{2}:\\d{2}";
	public static final String REGEX_DATETIME = REGEX_DATE + " " + REGEX_TIME;
	public static final String REGEX_DATE_OR_DATETIME = REGEX_DATE + "( " + REGEX_TIME + ")?";

	public static final String REGEX_IP = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}";
	public static final String REGEX_IP_PORT = REGEX_IP + ":\\d{1,5}";
	
	/** 汉字字符[一-龥]，中文标点不算。 */
	public static final String REGEX_CHINESE_CHAR = "[\u4E00-\u9FA5]";
	
	/** 全体为纯汉字[一-龥]，中文标点不算。 */
	public static final String REGEX_CHINESE_TEXT = "^" + REGEX_CHINESE_CHAR + "+$";
	
	/** 匹配除英文字母和纯汉字[一-龥]之外的其它字符，可以是数字、空白符、中英文标点等等。 */
	public static final String REGEX_NOT_ENG_NOT_CHI_CHAR = "[^a-zA-Z\u4E00-\u9FA5]";

	/** 全体不包含英文字母和纯汉字[一-龥] */
	public static final String REGEX_NOT_ENG_NOT_CHI_TEXT = "^" +
			REGEX_NOT_ENG_NOT_CHI_CHAR + "+$";

	/** 匹配广义的非词字符（除英文字母、数字、纯汉字[一-龥]之外的其它字符），包括空白符、中英文标点等等。*/
	public static final String REGEX_NOT_WORD_CHAR = "[^a-zA-Z\\d\u4E00-\u9FA5]";
	
	/** 表示分隔、断句等含义的标点符号 */
	public static final String REGEX_PUNCTUATION_SEPARATION = "[,，.。:：;；]";

	/**【已迁移至TextConstants中，等UserPortal的v1.1.1上线后可以删除】<br>
	 * 作为一个用户标识，当业务系统以非人工方式变更数据时，用它填充到创建人、修改人之类的字段。*/
	@Deprecated
	public static final String SYS_AUTO = "sys_auto";

	/** yyyy-MM-dd HH:mm:ss */
	public static final String FORMAT_STANDARD_DAF = "yyyy-MM-dd HH:mm:ss";
	/** yyyy-MM-dd */
	public static final String FORMAT_DATE_DAF = "yyyy-MM-dd";
	
	
	@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
	private static final Map<String,Object> UNUSED_MAP_SO = new HashMap<>(0);
	@SuppressWarnings("unchecked")
	public static final Class<Map<String,Object>> CLASS_MAP_SO =
			(Class<Map<String,Object>>) UNUSED_MAP_SO.getClass();
	
	@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
	private static final Map<String,String> UNUSED_MAP_SS = new HashMap<>(0);
	@SuppressWarnings("unchecked")
	public static final Class<Map<String,String>> CLASS_MAP_SS =
			(Class<Map<String,String>>) UNUSED_MAP_SS.getClass();
	
	
	/** 用于存储运行时创建的常量 */
	private static final Map<String,Object> runtimeConstantContainer = new ConcurrentHashMap<>();
	
	/** 【迁移到setRuntimeConstant】新增一个运行时常量，以后可以通过getRuntimeConstant方法获取。*/
	@Deprecated
	public static void addRuntimeConstant(String key, Object value) {
		runtimeConstantContainer.put(key, value);
	}

	/** 设置（添加或者更新）一个运行时常量，以后可以通过getRuntimeConstant方法获取。*/
	public static void setRuntimeConstant(String key, Object value) {
		if (value != null) {
			runtimeConstantContainer.put(key, value);
		} else {
			runtimeConstantContainer.remove(key);
		}
	}

	/** 删除一个运行时常量 */
	public static void delRuntimeConstant(String key) {
		runtimeConstantContainer.remove(key);
	}

	/** 获取运行时常量值 */
	@Deprecated
	public static Object getRuntimeConstant(String key) {
		return runtimeConstantContainer.get(key);
	}

	/**
	 * 获取运行时常量值，若常量池中无值（没有这个键或者值为null），
	 * 则执行函数生成一个值返回，并且将该值放入常量池（仅当得到非null值时才会放入）。
	 */
	public static <V> V getRuntimeConstant(String key, Supplier<V> generateValue) {
		return (V) runtimeConstantContainer.computeIfAbsent(key, unusedKey -> generateValue.get());
	}

	/** yyyy-MM-dd HH:mm:ss */
	public static DateFormat getStandardDaf() {
		return new SimpleDateFormat(FORMAT_STANDARD_DAF);
	}
	
	/** yyyy-MM-dd */
	public static DateFormat getDateDaf() {
		return new SimpleDateFormat(FORMAT_DATE_DAF);
	}
	
	/** #0.00 */
	public static DecimalFormat getDef() {
		return new DecimalFormat("#0.00");
	}

}